#include <linux/init.h>
#include <linux/types.h>
#include <linux/idr.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/major.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/rcupdate.h>
#include <linux/cdev.h>  
#include <linux/interrupt.h> 
#include <linux/ioctl.h>  
#include <linux/gpio.h>  
#include <linux/delay.h>
#include "24l01.h"
#define DEVICE_NAME "nrf24l01"              //设备名称
#define IRQNUM      (IRQ_GPIO_START+0xC4)   //中断号 PG4

int light_major = 300; 
static struct class *firstdrv_class;  
static struct device *firstdrv_device;  


static void NRF2401_Delay(u32 ul_Nops)
{
	u32 i;
	for(i=0;i<ul_Nops;i++)
	{
		asm ( "nop" ) ;
    }
}
static u8 NRF24L01_SendByte(u8 dat)
{
	u8 i;
	for (i = 0; i < 8; i++) 
	{
		//发送1位数据
		if (dat & 0x80)         
		{
		    Set_MOSI;
		    //NRF2401_Delay(5);
		}
		else
		{
		    Clr_MOSI;
		    //NRF2401_Delay(5);
		}
		dat <<= 1;           
		//读取1位数据
		Set_SCK;     
		//NRF2401_Delay(5);
		if (MISO_IN)
		{
		    dat |= 1;
		}             
		else
		{
		    dat &= 0xFE;
		}
		//NRF2401_Delay(5);
		Clr_SCK;  
        	//NRF2401_Delay(5);
	}
	return(dat);                 
}
void LNRF24L01_Init(void)
{
	u8 addr_tx[5] = {INIT_ADDR_TX};
	u8 addr_rx[5] = {INIT_ADDR_RX};
	u8 read;
	//--------------------------------------IO及中断初始化-----------------------------------------//
	gpio_request(NUC970_PB12, "NUC970_PB12");
	gpio_direction_output(NUC970_PB12,0);

	gpio_request(NUC970_PB13, "NUC970_PB13");
	gpio_direction_output(NUC970_PB13,0);

	gpio_request(NUC970_PB14, "NUC970_PB14");
	gpio_direction_output(NUC970_PB14,0);

	gpio_request(NUC970_PB15, "NUC970_PB15");
	gpio_direction_input(NUC970_PB15);

	gpio_request(NUC970_PG4, "NUC970_PG4");
	gpio_direction_input(NUC970_PG4);

	gpio_request(NUC970_PG5, "NUC970_PG5");
	gpio_direction_output(NUC970_PG5,0);
	udelay(100);	
		
	//--------------------------------------NRF24L01寄出去配置-----------------------------------------//
	L01_CE_HIGH;
	L01_ClearIRQ(IRQ_ALL);
	#if DYNAMIC_PACKET == 1
	//dynamic payload length
	L01_WriteSingleReg(L01REG_DYNPD, (1<<0));//Enable pipe 0 dynamic payload length
	L01_WriteSingleReg(L01REG_FEATRUE, 0x07);
	L01_ReadSingleReg(L01REG_DYNPD);
	L01_ReadSingleReg(L01REG_FEATRUE);
	#elif DYNAMIC_PACKET == 0
	//Fixed packet length
	L01_WriteSingleReg(L01REG_RX_PW_P0, FIXED_PACKET_LEN);
	#endif//DYNAMIC_PACKET

	L01_WriteSingleReg(L01REG_CONFIG, /*(1<<MASK_RX_DR) |*///receive interrupt
		                      (1<<EN_CRC) |    //Enable CRC, 1 byte
		                      (1<<PWR_UP));    //Power up the device
	L01_WriteSingleReg(L01REG_EN_AA, (1<<ENAA_P0));    //Auto ack in pipe 0
	L01_WriteSingleReg(L01REG_EN_RXADDR, (1<<ERX_P0)); //Enable pipe 0 receive
	L01_WriteSingleReg(L01REG_SETUP_AW, AW_5BYTES);    //Address width : 5Byte
	L01_WriteSingleReg(L01REG_RETR, ARD_4000US |(REPEAT_CNT & 0x0F));          //repeat wait : 250us
	//L01_WriteSingleReg(L01REG_RF_CH, 60);              //Initial channel
	L01_WriteSingleReg(L01REG_RF_SETUP, 0x26);
	L01_SetPower(P_0DBM);
	L01_SetTXAddr(addr_tx, 5);                        //Set TX address
	L01_SetRXAddr(0, addr_rx, 5);                     //Set RX address
	
	L01_SetTRMode(RX_MODE);     //设置为接收模式
	L01_WriteHoppingPoint(30);  //设置通道号为30
	L01_SetSpeed(SPD_2M);       //设置波特率为2M
	
}
u8 NRF24L01_ReadBuf(u8 *pBuf)
{
	u8	Len = 0;
	Len = L01_ReadRXPayload(pBuf);                        
	return(Len);                   
}
void NRF24L01_TxPacket(u8 *tx_buf, u8 len)
{		
	L01_CE_LOW;// CE = 0,启动发射
	//L01_FlushRX();
	L01_FlushTX();
	L01_WriteTXPayload_Ack(tx_buf,len);
	L01_CE_HIGH;// CE = 1,启动发射
}
void NRF24L01_TxPacket2(u8 *tx_buf, u8 len)
{		
	u8 tmp = 0;
	L01_CE_LOW;// CE = 0,启动发射
	//L01_FlushRX();
	L01_FlushTX();
	L01_WriteTXPayload_Ack(tx_buf,len);
	L01_CE_HIGH;// CE = 1,启动发射

	while(IRQ_IN != 0);
	while((tmp = L01_ReadIRQSource()) == 0);
	//L01_CE_LOW;// CE = 0,节能
	L01_ClearIRQ(IRQ_ALL);
	
	if( tmp & ( 1<<TX_DS ) )
	{  
		tmp = 1;		
	}
	if( tmp & ( 1<<MAX_RT ) )
	{
		tmp = 2;	
	}
	if( tmp & ( 1<<RX_DR )  )
	{
		 tmp =31;	
	}
}
u8 L01_ReadRPDReg(void)
{
	u8 uch_Temp;
	L01_CSN_LOW;
	SPI_ExchangeByte(L01REG_RPD);
	uch_Temp = SPI_ExchangeByte(0xFF);
	L01_CSN_HIGH;
	uch_Temp = (uch_Temp&(1<<RPD));
	return(uch_Temp);
}
//=======================================以下为NRF24L01内部驱动函数================================// 
//Read a single register of nRF24L01
//param Addr, The address of the register
//param The value read from the register
u8 L01_ReadSingleReg(u8 Addr)
{
    u8 btmp;
    L01_CSN_LOW;
    SPI_ExchangeByte(R_REGISTER | Addr);
    btmp = SPI_ExchangeByte(0xFF);
    L01_CSN_HIGH;
    return btmp;
}


//Read several registers of nRF24L01
//param StartAddr, The start address of the registers
//param nBytes, How many registers do you want to read
//param pBuff, The buffer to save the values
void L01_ReadMultiReg(u8 StartAddr, u8 nBytes, u8 *pBuff)
{
    u8 btmp;
    L01_CSN_LOW;
    SPI_ExchangeByte(R_REGISTER | StartAddr);
    for(btmp = 0; btmp < nBytes; btmp ++)
    {
      *(pBuff + btmp) = SPI_ExchangeByte(0xFF);
    }
    L01_CSN_HIGH;
}

//Write a single byte to a register
//param Addr, The address of the register
//param Value, The value to be written
void L01_WriteSingleReg(u8 Addr, u8 Value)
{
    L01_CSN_LOW;
    SPI_ExchangeByte(W_REGISTER | Addr);
    SPI_ExchangeByte(Value);
    L01_CSN_HIGH;
}

//Read several registers of nRF24L01
//param StartAddr, The start address of the registers
//param pBuff, The buffer store the values
//param Length, How many registers do you want to write
void L01_WriteMultiReg(u8 StartAddr, u8 *pBuff, u8 Length)
{
    u8 i;
    L01_CSN_LOW;
    SPI_ExchangeByte(W_REGISTER | StartAddr);
    for(i = 0; i < Length; i ++)
    {
        SPI_ExchangeByte(*(pBuff + i));
    }
    L01_CSN_HIGH;
}

//Flush the TX buffer
void L01_FlushTX(void)
{
    L01_CSN_LOW;
    SPI_ExchangeByte(FLUSH_TX);
    L01_CSN_HIGH;
}

//Flush the RX buffer
void L01_FlushRX(void)
{
    L01_CSN_LOW;
    SPI_ExchangeByte(FLUSH_RX);
    L01_CSN_HIGH;
}

//Reuse the last transmitted payload
void L01_ReuseTXPayload(void)
{
    L01_CSN_LOW;
    SPI_ExchangeByte(REUSE_TX_PL);
    L01_CSN_HIGH;
}

//nop operation of nRF24L01
void L01_Nop(void)
{
    L01_CSN_LOW;
    SPI_ExchangeByte(L01_NOP);
    L01_CSN_HIGH;
}

//Read statu register of nRF24L01
//param Statu register of nRF24L01
u8 L01_ReadStatusReg(void)
{
    u8 Status;
    L01_CSN_LOW;
    Status = SPI_ExchangeByte(R_REGISTER + L01REG_STATUS);
    L01_CSN_HIGH;
    return Status;
}

//Clear IRQ cuased by nRF24L01
void L01_ClearIRQ(u8 IRQ_Source)
{
    u8 btmp = 0;

    IRQ_Source &= (1<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT);
    btmp = L01_ReadStatusReg();
    L01_CSN_LOW;
    SPI_ExchangeByte(W_REGISTER + L01REG_STATUS);
    SPI_ExchangeByte(IRQ_Source | btmp);
    L01_CSN_HIGH;
    L01_ReadStatusReg();
}

//Read the IRQ source of nRF24L01+
//param IRQ source mask code
u8 L01_ReadIRQSource(void)
{
    return (L01_ReadStatusReg() & ((1<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT)));
}

//Read the payload width of the top buffer of FIFO
//param The width of the pipe buffer
u8 L01_ReadTopFIFOWidth(void)
{
    u8 btmp;
    L01_CSN_LOW;
    SPI_ExchangeByte(R_RX_PL_WID);
    btmp = SPI_ExchangeByte(0xFF);
    L01_CSN_HIGH;
    return btmp;
}

//Read the RX payload from internal buffer
//param pBuff, buffer to store the data
//param The length of data read
u8 L01_ReadRXPayload(u8 *pBuff)
{
    u8 width, PipeNum;
    PipeNum = (L01_ReadSingleReg(L01REG_STATUS) >> 1) & 0x07;
    width = L01_ReadTopFIFOWidth();

    L01_CSN_LOW;
    SPI_ExchangeByte(R_RX_PAYLOAD);
    for(PipeNum = 0; PipeNum < width; PipeNum ++)
    {
      *(pBuff + PipeNum) = SPI_ExchangeByte(0xFF);
    }
    L01_CSN_HIGH;
    L01_FlushRX();
    return width;
}

//Write TX payload to a pipe and prx will return ack back
//param PipeNum, number of the pipe
//param pBuff, A buffer stores the data
//param nBytes, How many bytes to be wrote to
void L01_WriteTXPayload_Ack(u8 *pBuff, u8 nBytes)
{
    u8 btmp;
    u8 length = (nBytes > 32) ? 32 : nBytes;

    L01_FlushTX();
    L01_CSN_LOW;
    SPI_ExchangeByte(W_TX_PAYLOAD);
    for(btmp = 0; btmp < length; btmp ++)
    {
        SPI_ExchangeByte(*(pBuff + btmp));
    }
    L01_CSN_HIGH;
}

//write data in tx mode, and prx won't return ack back
//param Data, A buffer stores the address data
//param Data_Length, How many bytes of the data buff
void L01_WriteTXPayload_NoAck(u8 *Data, u8 Data_Length)
{
    if(Data_Length > 32 || Data_Length == 0)
    {
        return ;
    }
    L01_CSN_LOW;
    SPI_ExchangeByte(W_TX_PAYLOAD_NOACK);
    while(Data_Length--)
    {
        SPI_ExchangeByte(*Data++);
    }
    L01_CSN_HIGH;
}

//write data in tx fifo when rx mode
//param Data, A buffer stores the address data
//param Data_Length, How many bytes of the data buff
void L01_WriteRXPayload_InAck(u8 *pData, u8 Data_Length)
{
    u8 length = (Data_Length > 32) ? 32 : Data_Length;
    u8 btmp;

    L01_CSN_LOW;
    SPI_ExchangeByte(W_ACK_PAYLOAD);
    for(btmp = 0; btmp < length; btmp ++)
    {
        SPI_ExchangeByte(*(pData + btmp));
    }
    L01_CSN_HIGH;
}

//Write address for the own device
//param pAddr, A buffer stores the address data
//param Addr_Length, How many bytes of the address
void L01_SetTXAddr(u8 *pAddr, u8 Addr_Length)
{
    u8 Length = (Addr_Length > 5) ? 5 : Addr_Length;
    L01_WriteMultiReg(L01REG_TX_ADDR, pAddr, Length);
}

//Write address for a RX pipe
//param PipeNum, number of the pipe
//param pAddr, A buffer stores the address data
//param Addr_Length, How many bytes of the address
void L01_SetRXAddr(u8 PipeNum, u8 *pAddr, u8 Addr_Length)
{
    u8 Length = (Addr_Length > 5) ? 5 : Addr_Length;
    u8 pipe = (PipeNum > 5) ? 5 : PipeNum;

    L01_WriteMultiReg(L01REG_RX_ADDR_P0 + pipe, pAddr, Length);
}

//Send the communication speed of the RF device
void L01_SetSpeed(L01SPD speed)
{
	u8 btmp = L01_ReadSingleReg(L01REG_RF_SETUP);

	btmp &= ~((1<<5) | (1<<3));
	if(speed == SPD_250K)		//250K
	{
		btmp |= (1<<5);
	}
	else if(speed == SPD_1M)  //1M
	{
   		btmp &= ~((1<<5) | (1<<3));
	}
	else if(speed == SPD_2M)  //2M
	{
		btmp |= (1<<3);
	}

	L01_WriteSingleReg(L01REG_RF_SETUP, btmp);
}

//Send the transmitt power of the device
//param power
void L01_SetPower(L01PWR power)
{
    u8 btmp = L01_ReadSingleReg(L01REG_RF_SETUP) & ~0x07;
    switch(power)
    {
        case P_F18DBM:
            btmp |= PWR_18DB;
            break;
        case P_F12DBM:
            btmp |= PWR_12DB;
            break;
        case P_F6DBM:
            btmp |= PWR_6DB;
            break;
        case P_0DBM:
            btmp |= PWR_0DB;
            break;
        default:
            break;
    }
    L01_WriteSingleReg(L01REG_RF_SETUP, btmp);
}

//Set frequency for the device,must be 0-125
//param FreqPoint, The hopping point
void L01_WriteHoppingPoint(u8 FreqPoint)
{
    L01_WriteSingleReg(L01REG_RF_CH, FreqPoint & 0x7F);
}


//Set the device as TX or RX mode
//param mode, the mode to be set
//TX_MODE, TX mode
//RX_MODE, RX mode
void L01_SetTRMode(L01MD mode)
{
    u8 controlreg = L01_ReadSingleReg(L01REG_CONFIG);
    if(mode == TX_MODE)       { controlreg &= ~(1<<PRIM_RX); }
    else if(mode == RX_MODE)  { controlreg |= (1<<PRIM_RX); }

    L01_WriteSingleReg(L01REG_CONFIG, controlreg);
}

//Initialize the nRF24L01
void L01_Init(void)
{
    u8 addr[5] = {INIT_ADDR};

    L01_CE_HIGH;
    L01_ClearIRQ(IRQ_ALL);
#if DYNAMIC_PACKET == 1
   //dynamic payload length
    L01_WriteSingleReg(L01REG_DYNPD, (1<<0));//Enable pipe 0 dynamic payload length
    L01_WriteSingleReg(L01REG_FEATRUE, 0x07);
    L01_ReadSingleReg(L01REG_DYNPD);
    L01_ReadSingleReg(L01REG_FEATRUE);
#elif DYNAMIC_PACKET == 0
   //Fixed packet length
    L01_WriteSingleReg(L01REG_RX_PW_P0, FIXED_PACKET_LEN);
#endif//DYNAMIC_PACKET

    L01_WriteSingleReg(L01REG_CONFIG, /*(1<<MASK_RX_DR) |*///receive interrupt
                                      (1<<EN_CRC) |    //Enable CRC, 1 byte
                                      (1<<PWR_UP));   //Power up the device
    L01_WriteSingleReg(L01REG_EN_AA, (1<<ENAA_P0));  //Auto ack in pipe 0
    L01_WriteSingleReg(L01REG_EN_RXADDR, (1<<ERX_P0));//Enable pipe 0 receive
    L01_WriteSingleReg(L01REG_SETUP_AW, AW_5BYTES);    //Address width : 5Byte
    L01_WriteSingleReg(L01REG_RETR, ARD_4000US |
                        (REPEAT_CNT & 0x0F));        //repeat wait : 250us
    L01_WriteSingleReg(L01REG_RF_CH, 60);            //Initial channel
    L01_WriteSingleReg(L01REG_RF_SETUP, 0x26);
	//L01_SetPower(P_F12DBM);
    L01_SetTXAddr(&addr[0], 5);                         //Set TX address
    L01_SetRXAddr(0, &addr[0], 5);                      //Set RX address
}




struct nrf24l01_data 
{
	struct cdev cdev;  
	char recvbuf[64];
	int  recvlen;
};
struct nrf24l01_data *my24l01;

static irqreturn_t nrf24l01_interrupt(int irq, void *dev_id)
{
	static int kn1 = 0;
	static int kn2 = 0;
	static int kn3 = 0;	
	static char buff[64]={0};
	//临时变量
	u8 uch_Len = 0;
	u8 uch_Temp = 0;

	struct nrf24l01_data *io_irqs = (struct nrf24l01_data *)dev_id;

	uch_Temp = L01_ReadIRQSource();
	//判断中断类型
	if( uch_Temp & ( 1<<TX_DS ) )         //Data sent TX FIFO interrupt
	{
		kn1++;
		printk("\t发送成功!\n");
	}
	else if( uch_Temp & ( 1<<MAX_RT ) )   //Maximum number of TX retransmits interrupt
	{
		kn2++;
		printk("\t发送失败,未回应!\n");
	}
	else if( uch_Temp & ( 1<<RX_DR )  )   //Data ready RX FIFO interrupt
	{
		uch_Len = NRF24L01_ReadBuf(buff);
		if(uch_Len > 0)
		{
			kn3++;
			memcpy(io_irqs->recvbuf,buff,uch_Len);
			io_irqs->recvlen = uch_Len;
		}
	}
	L01_ClearIRQ( IRQ_ALL );
	
	return IRQ_HANDLED;
}
static int nrf24l01_open(struct inode *inode, struct file *file)
{
    	int err = 0;

	file->private_data = container_of(inode->i_cdev,struct nrf24l01_data,cdev); 
        /*注册中断函数*/
	err = request_irq(IRQNUM, nrf24l01_interrupt, IRQF_TRIGGER_FALLING, "nrf24l01", my24l01);
	if (err)
	{
		/*如果出错，释放已经注册的中断，并返回*/
		disable_irq(IRQNUM);
		free_irq(IRQNUM, my24l01);
		return -EBUSY;
	}
	/*正常返回*/
	LNRF24L01_Init();

	return 0;
}
static int nrf24l01_close(struct inode *inode, struct file *file)
{
    free_irq(IRQNUM, my24l01);
    return 0;
}
static int nrf24l01_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
	unsigned long err;

	struct nrf24l01_data *dev = filp->private_data; 
	int len = dev->recvlen;
	/*传递到用户空间*/
	err = copy_to_user(buff, (const void *)(dev->recvbuf), dev->recvlen);

	dev->recvlen = 0;

	return len;
}
static int nrf24l01_write(struct file *filp,const char __user *buff, size_t count, loff_t *offp)
{
	unsigned long err;
	char buf[50];

	//struct nrf24l01_data *dev = filp->private_data; 
		
	if(copy_from_user(&buf, buff, count))
	{
		printk("Can't Send Data !");
 		return -EFAULT;
	}

	NRF24L01_TxPacket2((u8*)buf, count);

	return count;
}
static long nrf24l01_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
    int err = 0;
    //void __user *argp = (void __user *)arg;
    /* Verify user arguments. */
    //if (_IOC_TYPE(cmd) != GPIO_TEST_IOC_MAGIC)
    //    return -ENOTTY;

    char address[6];
 
    switch (cmd) 
	{
    case 1:
        printk("set channel %d\n",arg);
        if (arg > 9999) 
	{
            printk("set channel error\n");
            err = -EFAULT;
            break;
        }
	L01_WriteHoppingPoint(arg);
        break;
   case 2:
        printk("set mode %d\n",arg);
        if (arg > 2) 
	{
            printk("set mode error\n");
            err = -EFAULT;
            break;
        }
	L01_SetTRMode(arg);
        break;
   case 3:
	copy_from_user((unsigned char *)address,(unsigned char *)arg,6);

        printk("set tx address %x %x %x %x %x\n",address[0],address[1],address[2],address[3],address[4]);
        if (0) 
	{
            printk("set address error\n");
            err = -EFAULT;
            break;
        }
	L01_SetTXAddr(address, 5);  
        break;
   case 4:
	copy_from_user((unsigned char *)address,(unsigned char *)arg,6);

        printk("set rx address %x %x %x %x %x\n",address[0],address[1],address[2],address[3],address[4]);
        if (0) 
	{
            printk("set address error\n");
            err = -EFAULT;
            break;
        }
	L01_SetRXAddr(0, address, 5); 
        break;
    default:
        printk("Invalid ioctl command.\n");
        return -ENOTTY;
    }
 
    return err;
 }
 
/*设备操作集*/
static struct file_operations dev_fops = {
    .owner = THIS_MODULE,
    .open = nrf24l01_open,
    .release = nrf24l01_close,
    .read = nrf24l01_read,
    .write = nrf24l01_write,
    .unlocked_ioctl = nrf24l01_ioctl,
};

static void nrf24l01_setup_cdev(struct nrf24l01_data *dev,int index)  
{  
    int err,devno = MKDEV(light_major,index);  
  
    cdev_init(&dev->cdev,&dev_fops);  
    dev->cdev.owner = THIS_MODULE;  
    dev->cdev.ops = &dev_fops;  
  
    err = cdev_add(&dev->cdev,devno,1);  
  
    if(err)  
    {  
        printk(KERN_NOTICE "Error %d adding nrf24l01",err);  
    }  
} 
int nrf24l01_init(void)  
{  
    int result=0;  
  
    dev_t dev = MKDEV(light_major,0);  
    if(light_major)  
    {  
          
        result = register_chrdev_region(dev,1,"24_l01");  
	firstdrv_class = class_create(THIS_MODULE, "nrf24l01");  
	firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(light_major, 0), NULL, DEVICE_NAME);
    }  
  
    if(result < 0)  
    {  
        return result;  
    }  
  
    my24l01 = kmalloc(sizeof(struct nrf24l01_data),GFP_KERNEL);  
    if(!my24l01)  
    {  
        result = - ENOMEM;  
        unregister_chrdev_region(dev,1);   
	return result;
    }  
    memset(my24l01,0,sizeof(struct nrf24l01_data));  
    nrf24l01_setup_cdev(my24l01,0);  
    return 0;  
} 

/*注销设备*/
static void __exit dev_exit(void)
{
	cdev_del(&my24l01->cdev);     
	kfree(my24l01);  
	unregister_chrdev_region(MKDEV(light_major,0),1); 
	device_unregister(firstdrv_device);  //卸载类下的设备  
   	class_destroy(firstdrv_class);      //卸载类  
}
module_init(nrf24l01_init); //模块初始化，仅当使用insmod/podprobe 命令加载时有用，如果设备不是通过模块方式加载，此处将不会被调用

module_exit(dev_exit); //卸载模块，当该设备通过模块方式加载后，可以通过rmmod 命令卸载，将调用此函数

MODULE_LICENSE("GPL");//版权信息

MODULE_AUTHOR("Madest Inc.");//作者名字


